package ar.uba.is2.ec.trmanager;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import ar.uba.is2.common.mensaje.Componente;
import ar.uba.is2.common.mensaje.Mensaje;
import ar.uba.is2.common.mensaje.Receptor;
import ar.uba.is2.common.threads.ThreadManager;
import ar.uba.is2.ec.config.Contexto;

public class ReceptorHeartbit implements Receptor {

	private Logger log = Logger.getLogger(ReceptorHeartbit.class);
	private static final long TIME_TO_LIVE = Long.parseLong(Contexto.instance.get("tiempo.caida.TR"));
	private Map<Componente, Date> lastHeartbit;

	public ReceptorHeartbit() {
		this.lastHeartbit = new HashMap<Componente, Date>();

		log.debug("el tiempo para que una TR sea dado de baja es:" + TIME_TO_LIVE);
		DetectorTrMuertaDaemon daemon = new DetectorTrMuertaDaemon();

		ThreadManager.instance.crearYCorrerThread(daemon);
	}

	public void recibirMensaje(Mensaje mensaje) {
		Componente origen = mensaje.getOrigen();
		lastHeartbit.put(origen, new Date());
	}

	private void analisarUltimosHearbits() {
		Date now = new Date();
		
		for (Entry<Componente, Date> lastHeartbit : this.lastHeartbit.entrySet()) {
			if( timeout(lastHeartbit.getValue(), now)){
				lanzarAlarmaTrCaida(lastHeartbit.getKey());
			}
		}
	}

	private void lanzarAlarmaTrCaida(Componente terminalRemota) {
		log.info("**** TR CAIDA " + terminalRemota.getNombre());
		log.debug("Triangulando...");
	}

	private boolean timeout(Date lastHeartbit, Date now) {
		return now.getTime() - lastHeartbit.getTime() > TIME_TO_LIVE;
	}

	private class DetectorTrMuertaDaemon implements Runnable {

		private static final long HEARBIT_TIME = 30000l;

		public synchronized void run() {
			try {
				while (true) {
					analisarUltimosHearbits();

					this.wait(HEARBIT_TIME);
				}
			} catch (InterruptedException e) {
			}
		}
	}
}
